﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Easy.Model;

namespace Easy.Operation.Expression
{
    /// <summary>
    /// 表达式转换类型
    /// </summary>
    public class ExpressionConvert
    {
        private string EntityName;
        private Dictionary<string, Field> Fields;
        private Guid CurrentUserId;
        private Guid CurrentBusinessId;

        public ExpressionConvert(string entityName, Dictionary<string, Field> fields, Guid currentUserId, Guid currentBusinessId)
        {
            this.EntityName = entityName;
            this.Fields = fields;
            this.CurrentUserId = currentUserId;
            this.CurrentBusinessId = currentBusinessId;
        }

        /// <summary>
        /// 过滤转换
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public string FilterConvert(FilterExpression filter)
        {
            string where = "({0} {1})";

            if (filter.Filters != null)
            {
                StringBuilder sb_filter = new StringBuilder();

                //foreach (var item in filter.Filters)
                for (int i = 0; i < filter.Filters.Count; i++)
                {
                    //如果Conditions为空，一开始的FilterOperator不添加
                    if (!(filter.Conditions.Count == 0 && i == 0))
                    {
                        sb_filter.Append(filter.FilterOperator.ToString());
                    }

                    sb_filter.Append(FilterConvert(filter.Filters[i]));
                }

                if (!(ConditionsJoin(filter.FilterOperator.ToString(), filter.Conditions) == "" && sb_filter.ToString() == ""))
                {
                    where = string.Format(where, ConditionsJoin(filter.FilterOperator.ToString(), filter.Conditions), sb_filter.ToString());
                }
                else
                {
                    where = "";
                }
            }
            else
            {
                if (ConditionsJoin(filter.FilterOperator.ToString(), filter.Conditions) != "")
                {
                    where = string.Format(where, ConditionsJoin(filter.FilterOperator.ToString(), filter.Conditions), "");
                }
                else
                {
                    where = "";
                }
            }
            return where;
        }

        public string ConditionsJoin(string logicalOperator, List<ConditionExpression> conditions)
        {
            StringBuilder joinConditions = new StringBuilder();
            string returns = "";
            foreach (ConditionExpression item in conditions)
            {
                string conditionvonvert = ConditionConvert(item);
                if (conditionvonvert != "")
                {
                    joinConditions.Append(conditionvonvert + logicalOperator);
                }
            }
            if (joinConditions.ToString() != "")
            {
                returns = joinConditions.ToString().Substring(0, joinConditions.ToString().Length - logicalOperator.Length);
            }
            return returns;
        }

        /// <summary>
        /// 条件转换
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public string ConditionConvert(ConditionExpression condition)
        {
            string expression = " t.{0} {1} {2} ";

            ////如果是lookup类型的，名称换下
            string AttributeName = condition.AttributeName.ToLower();
            if (!Fields.ContainsKey(AttributeName))
            {
                new Exception(string.Format("ConditionConvert Error : AttributeName({0}) not in Entity({1})", AttributeName, this.EntityName)); 
            }
           
            string valueline = "";
            FieldCategoryType fieldCategoryType = GetFiledCategoryType(this.Fields[AttributeName].Type);
            FieldType fieldType = this.Fields[AttributeName].Type.Value;
            //值为多个 in和not in
            if (condition.Operator == ConditionOperator.In || condition.Operator == ConditionOperator.NotIn)
            {
                valueline = " ({0})";
                StringBuilder Manyvalues = new StringBuilder();

                //string Manyvalues = "";
                for (int i = 0; i < condition.Values.Count; i++)
                {
                    if (i != condition.Values.Count - 1)
                    {
                        if (fieldCategoryType == FieldCategoryType.Number)
                        {
                            string number = ConvertNumber(fieldType, condition.Values[i].ToString());
                            Manyvalues.Append(number + ",");
                        }
                        else if (fieldCategoryType == FieldCategoryType.Lookup)
                        {
                            EntityReference lookup = condition.Values[i] as EntityReference;
                            if (lookup == null)
                            {
                                lookup = JsonConvert.DeserializeObject<EntityReference>(condition.Values[i].ToString());
                            }


                            if (lookup.id != null)
                            {
                                Manyvalues.Append("'" + lookup.id + "' , ");
                            }
                            else
                            {
                                Manyvalues.Append("'" + lookup.name.Replace("'", "''") + "' , ");
                                AttributeName = AttributeName + "Name";
                            }
                        }
                        else
                        {
                            string s = condition.Values[i].ToString().Replace("'", "''");
                            Manyvalues.Append("'" + s + "' , ");
                        }
                    }
                    else
                    {
                        if (fieldCategoryType == FieldCategoryType.Number)
                        {
                            string number = ConvertNumber(fieldType, condition.Values[i].ToString());
                            Manyvalues.Append(number);
                        }
                        else if (fieldCategoryType == FieldCategoryType.Lookup)
                        {
                            EntityReference lookup = condition.Values[i] as EntityReference;
                            if (lookup == null)
                            {
                                lookup = JsonConvert.DeserializeObject<EntityReference>(condition.Values[i].ToString());
                            }
                            if (lookup.id != null)
                            {
                                Manyvalues.Append("'" + lookup.id + "'");
                            }
                            else
                            {
                                Manyvalues.Append("'" + lookup.name.Replace("'", "''") + "'");
                                AttributeName = AttributeName + "Name";
                            }
                        }
                        else
                        {
                            string s = condition.Values[i].ToString().Replace("'", "''");
                            Manyvalues.Append("'" + s + "'");
                        }
                    }
                }
                valueline = string.Format(valueline, Manyvalues);
            }
            //值2个  between和not between
            else if (condition.Operator == ConditionOperator.Between || condition.Operator == ConditionOperator.NotBetween)
            {
                valueline = "{0} and {1} ";
                string man;
                for (int i = 0; i < 2; i++)
                {
                    if (fieldCategoryType == FieldCategoryType.Number)
                    {
                        string number = ConvertNumber(fieldType, condition.Values[i].ToString());
                        man = number;
                    }
                    else
                    {
                        string s = condition.Values[i].ToString().Replace("'", "''");
                        man = "'" + s + "'";
                    }
                    if (i == 0)
                    {
                        valueline = string.Format(valueline, man, "{0}");
                    }
                    else
                    {
                        valueline = string.Format(valueline, man);
                    }
                }
            }
            //值0个  null和not null
            else if (condition.Operator == ConditionOperator.Null || condition.Operator == ConditionOperator.NotNull)
            {
                valueline = "";
            }
            //nvarchar 的长度比较
            else if (condition.Operator == ConditionOperator.Len)
            {
                if (this.Fields[AttributeName].Type == FieldType.nvarchar)
                {
                    expression = " {1}(t.{0})={2} ";
                    valueline = int.Parse(condition.Values[0].ToString()).ToString();
                }
                else
                {
                    expression = "";
                    valueline = "";
                }
            }
            else if (condition.Operator == ConditionOperator.EqualUserId ||  condition.Operator == ConditionOperator.NotEqualUserId)
            {
                valueline = "'" + this.CurrentUserId.ToString() + "' ";
            }
            else if (condition.Operator == ConditionOperator.EqualBusinessId || condition.Operator == ConditionOperator.NotEqualBusinessId)
            {
                valueline = "'" + this.CurrentBusinessId.ToString() + "' ";
            }
            //值1个 =,!=,<,<=,>,>=,like,not like
            else
            {
                valueline = "{0}";
                StringBuilder Manyvalues = new StringBuilder();
                string a = this.Fields[AttributeName].Type.ToString();
                if (fieldCategoryType == FieldCategoryType.Number)
                {
                    if (condition.Operator == ConditionOperator.Like)
                    {
                        expression = "";
                        valueline = "";
                    }
                    else
                    {
                        string number = ConvertNumber(fieldType, condition.Values[0].ToString());
                        Manyvalues.Append(number);
                    }
                }
                else if (fieldCategoryType == FieldCategoryType.Lookup)
                {
                    EntityReference lookup = condition.Values[0] as EntityReference;
                    if (lookup == null)
                    {
                        lookup = JsonConvert.DeserializeObject<EntityReference>(condition.Values[0].ToString());
                    }
                    if (lookup.id != null)
                    {
                        Manyvalues.Append("'" + lookup.id + "'");
                    }
                    else
                    {
                        string s = "";
                        if (condition.Operator == ConditionOperator.Like || condition.Operator == ConditionOperator.NotLike)
                        {
                            s = lookup.name.Replace("'", "''").Replace("*", "%") + "%";

                        }
                        else
                        {
                            s = lookup.name.Replace("'", "''");

                        }
                        Manyvalues.Append("'" + s + "'");

                        AttributeName = condition.AttributeName + "Name";
                    }
                }
                else
                {
                    string s = "";
                    if (condition.Operator == ConditionOperator.Like || condition.Operator == ConditionOperator.NotLike)
                    {
                        s = condition.Values[0].ToString().Replace("'", "''").Replace("*", "%") + "%";

                    }
                    else
                    {
                        s = condition.Values[0].ToString().Replace("'", "''");

                    }
                    Manyvalues.Append("'" + s + "'");
                }
                valueline = string.Format(valueline, Manyvalues);
            }

            //expression = string.Format(expression, AttributeName, EnumToSymbol(condition.Operator.ToString()), valueline);
            //modify:kyzhao 字段名加上[]
            expression = string.Format(expression, "["+AttributeName+"]", EnumToSymbol(condition.Operator.ToString()), valueline);
            return expression;
        }

        public string EnumToSymbol(string Operator)
        {
            string symbol = "";
            switch (Operator)
            {
                case "Between": symbol = " between "; break;
                case "Equal":
                case "EqualUserId":
                case "EqualBusinessId":
                    symbol = " = "; 
                    break;
                case "GreaterEqual": symbol = " >= "; break;
                case "GreaterThan": symbol = " > "; break;
                case "In": symbol = " in "; break;
                case "LessEqual": symbol = " <= "; break;
                case "LessThan": symbol = " < "; break;
                case "Like": symbol = " like "; break;
                case "NotBetween": symbol = " not between "; break;
                case "NotEqual":
                case "NotEqualUserId":
                case "NotEqualBusinessId": 
                    symbol = " <> "; 
                    break;
                case "NotIn": symbol = " not in "; break;
                case "NotLike": symbol = " not like "; break;
                case "NotNull": symbol = " is not null "; break;
                case "Null": symbol = " is null "; break;
                case "Len": symbol = " Len"; break;
                default: break;
            }
            return symbol;
        }



        /// <summary>
        /// 区分字段类型的分类类型：Number，Text，Lookup
        /// </summary>
        /// <param name="fieldType"></param>
        /// <returns></returns>
        public FieldCategoryType GetFiledCategoryType(FieldType? fieldType)
        {

            switch (fieldType)
            {
                case FieldType.@int:
                case FieldType.@float:
                case FieldType.picklist:
                case FieldType.bit:
                    return FieldCategoryType.Number;
                case FieldType.key:
                case FieldType.nvarchar:
                case FieldType.ntext:
                case FieldType.date:
                case FieldType.datetime:
                    return FieldCategoryType.Text;
                case FieldType.lookup:
                    return FieldCategoryType.Lookup;
                default:
                    return FieldCategoryType.Text;

            }
        }

        private string ConvertNumber(FieldType ftype,string number)
        {
            string retNumber = "0";
            if (ftype == FieldType.@float)
            {
                float f;
                if (float.TryParse(number, out f))
                {
                    retNumber = f.ToString();
                }
                else
                {
                    throw new Exception("Convert to float error[" + number + "]");
                }
            }
            else if (ftype == FieldType.bit)
            {
                if (number == "0" || number.ToLower() == "false")
                {
                    retNumber = "0";
                }
                else if (number == "1" || number.ToLower() == "true")
                {
                    retNumber = "1";
                }
                else
                {
                    throw new Exception("Convert to bit error[" + number + "]");
                }
            }
            else
            {
                int i;
                if (int.TryParse(number, out i))
                {
                    retNumber = i.ToString();
                }
                else
                {
                    throw new Exception("Convert to int error[" + number + "]");
                }
            }
            return retNumber;
        }
    }
}
